﻿using AutoMapper;
using Enferno.Public.Web.Models;
using Enferno.StormApiClient.Customers;
using Enferno.StormApiClient.Shopping;

namespace Enferno.Public.Web.Mappers.CheckoutProfiles
{
    public class CheckoutToCheckoutModelProfile :
        CheckoutToCheckoutBaseModelProfile
            <CheckoutCompanyPayerModel, CheckoutCompanyShipToModel, CheckoutPrivatePayerModel,
                CheckoutPrivateShipToModel, CheckoutBuyerModel, PrivateCheckoutModel, CompanyCheckoutModel, BasketModel,
                BasketItemModel, PromotionModel, OnHandStatusModel, PriceModel, ProductFileModel, DeliveryMethodModel,
                PaymentMethodModel, PaymentServiceModel, PersonInformationModel, CompanyInformationModel, AddressModel>
    {
        
    }

    public class CheckoutToCheckoutBaseModelProfile<
        TCheckoutCompanyPayerModel,
        TCheckoutCompanyShipToModel,
        TCheckoutPrivatePayerModel,
        TCheckoutPrivateShipToModel,
        TCheckoutBuyerModel,
        TPrivateCheckoutModel,
        TCompanyCheckoutModel,
        TBasketModel,
        TBasketItemModel,
        TPromotionModel,
        TOnHandStatusModel,
        TPriceModel,
        TProductFileModel,
        TDeliveryMethodModel,
        TPaymentMethodModel,
        TPaymentServiceModel,        
        TPersonInformationModel,
        TCompanyInformationModel,
        TAddressModel> : Profile
        where TCheckoutCompanyPayerModel: CheckoutCompanyPayerBaseModel<TCompanyInformationModel, TAddressModel>
        where TCheckoutCompanyShipToModel: CheckoutCompanyShipToBaseModel<TCompanyInformationModel, TAddressModel>
        where TCheckoutPrivatePayerModel: CheckoutPrivatePayerBaseModel<TPersonInformationModel, TAddressModel>
        where TCheckoutPrivateShipToModel: CheckoutPrivateShipToBaseModel<TPersonInformationModel, TAddressModel>
        where TPrivateCheckoutModel : PrivateCheckoutBaseModel<TCheckoutPrivatePayerModel, TCheckoutPrivateShipToModel, TCheckoutBuyerModel, TBasketModel, TBasketItemModel, TPromotionModel, TOnHandStatusModel, TPriceModel, TProductFileModel, TDeliveryMethodModel, TPaymentMethodModel, TPaymentServiceModel, TPersonInformationModel, TAddressModel>
        where TCompanyCheckoutModel : CompanyCheckoutBaseModel<TCheckoutCompanyPayerModel, TCheckoutCompanyShipToModel, TCheckoutBuyerModel, TBasketModel, TBasketItemModel, TPromotionModel, TOnHandStatusModel, TPriceModel, TProductFileModel, TDeliveryMethodModel, TPaymentMethodModel, TPaymentServiceModel, TCompanyInformationModel, TAddressModel>
        where TBasketModel : BasketBaseModel<TBasketItemModel, TPromotionModel, TOnHandStatusModel, TPriceModel, TProductFileModel>
        where TBasketItemModel : BasketItemBaseModel<TPriceModel>
        where TPromotionModel : PromotionBaseModel<TProductFileModel>
        where TOnHandStatusModel : OnHandStatusModel
        where TPriceModel : PriceModel
        where TProductFileModel : ProductFileModel
        where TCheckoutBuyerModel : CheckoutBuyerModel
        where TDeliveryMethodModel : DeliveryMethodModel
        where TPaymentMethodModel : PaymentMethodBaseModel<TPaymentServiceModel>
        where TPaymentServiceModel : PaymentServiceModel
        where TPersonInformationModel : PersonInformationModel
        where TCompanyInformationModel : CompanyInformationModel
        where TAddressModel : AddressModel
    {
        protected override void Configure()
        {
            //Customer -> CheckoutPayerModel
            Mapper.CreateMap<Customer, CheckoutPayerBaseModel<TAddressModel>>()
                .ForMember(to => to.CustomerId, opts => opts.MapFrom(from => from.Id))
                .Include<Customer, TCheckoutPrivatePayerModel>()
                .Include<Customer, TCheckoutCompanyPayerModel>();

            Mapper.CreateMap<Customer, TCheckoutPrivatePayerModel>()
                .ForMember(to => to.PersonInformation,
                    opts => opts.MapFrom(from => Mapper.Map<Customer, TPersonInformationModel>(from)))
                .ForMember(to => to.SocialSecurityNumber, opts => opts.MapFrom(from => from.SSN));

            Mapper.CreateMap<Customer, TCheckoutCompanyPayerModel>()
                .ForMember(to => to.InvoiceAddress,
                    opts => opts.MapFrom(from => from.Companies != null && from.Companies.Count > 0
                        ? from.Companies[0].InvoiceAddress
                        : null))
                .ForMember(to => to.CompanyId,
                    opts =>
                        opts.MapFrom(
                            from => from.Companies != null && from.Companies.Count > 0
                                ? from.Companies[0].Id
                                : null))
                .ForMember(to => to.CompanyCode,
                    opts =>
                        opts.MapFrom(
                            from => from.Companies != null && from.Companies.Count > 0
                                ? from.Companies[0].Code
                                : null))
                .ForMember(to => to.CompanyInformation,
                    opts =>
                        opts.MapFrom(
                            from =>
                                from.Companies != null && from.Companies.Count > 0
                                    ? Mapper.Map<Company, TCompanyInformationModel>(from.Companies[0])
                                    : null))
                .ForMember(from => from.OrganisationNumber,
                    opts =>
                        opts.MapFrom(
                            from =>
                                from.Companies != null && from.Companies.Count > 0
                                    ? from.Companies[0].OrgNo
                                    : null));

            //CheckoutPayerModel -> Customer
            Mapper.CreateMap<CheckoutPayerBaseModel<TAddressModel>, Customer>()
                .ForMember(to => to.Id, opts => opts.MapFrom(from => from.CustomerId))
                .ForMember(to => to.Key, opts => opts.Ignore())
                .ForMember(to => to.Code, opts => opts.Ignore())
                .ForMember(to => to.SSN, opts => opts.Ignore())
                .ForMember(to => to.FirstName, opts => opts.Ignore())
                .ForMember(to => to.LastName, opts => opts.Ignore())
                .ForMember(to => to.Email, opts => opts.Ignore())
                .ForMember(to => to.Phone, opts => opts.Ignore())
                .ForMember(to => to.CellPhone, opts => opts.Ignore())
                .ForMember(to => to.ReferId, opts => opts.Ignore())
                .ForMember(to => to.ReferUrl, opts => opts.Ignore())
                .ForMember(to => to.Account, opts => opts.Ignore())
                .ForMember(to => to.Companies, opts => opts.Ignore())
                .ForMember(to => to.DeliveryAddresses, opts => opts.Ignore())
                .ForMember(to => to.Flags, opts => opts.Ignore())
                .ForMember(to => to.UseInvoiceAddressAsDeliveryAddress, opts => opts.Ignore())
                .ForMember(to => to.Info, opts => opts.Ignore())
                .ForMember(to => to.ExtensionData, opts => opts.Ignore())
                .Include<TCheckoutPrivatePayerModel, Customer>()
                .Include<TCheckoutCompanyPayerModel, Customer>();

            Mapper.CreateMap<TCheckoutPrivatePayerModel, Customer>()
                .ForMember(to => to.Email,
                    opts => opts.MapFrom(from => from.PersonInformation.Email))
                .ForMember(to => to.FirstName,
                    opts => opts.MapFrom(from => from.PersonInformation.FirstName))
                .ForMember(to => to.LastName,
                    opts => opts.MapFrom(from => from.PersonInformation.LastName))
                .ForMember(to => to.CellPhone,
                    opts => opts.MapFrom(from => from.PersonInformation.CellPhone))
                .ForMember(to => to.Phone,
                    opts => opts.MapFrom(from => from.PersonInformation.Phone))
                .ForMember(to => to.SSN, opts => opts.MapFrom(from => from.SocialSecurityNumber));

            Mapper.CreateMap<TCheckoutCompanyPayerModel, Customer>()
                .BeforeMap((from, to) =>
                {
                    var company = Mapper.Map<TCompanyInformationModel, Company>(from.CompanyInformation);
                    company.Id = from.CompanyId;
                    company.Code = from.CompanyCode;
                    company.OrgNo = from.OrganisationNumber;
                    company.InvoiceAddress = Mapper.Map<TAddressModel, Address>(from.InvoiceAddress);
                    to.Companies = new CompanyList {company};
                });

            //Customer -> CheckoutShipToModel
            Mapper.CreateMap<Customer, CheckoutShipToBaseModel<TAddressModel>>()
                .ForMember(to => to.CustomerId, opts => opts.MapFrom(from => from.Id))
                .ForMember(to => to.DeliveryAddress, opts => opts.Ignore())
                .Include<Customer, TCheckoutPrivateShipToModel>()
                .Include<Customer, TCheckoutCompanyShipToModel>();

            Mapper.CreateMap<Customer, TCheckoutPrivateShipToModel>()
                .ForMember(to => to.DeliveryAddress,
                    opts =>
                        opts.MapFrom(
                            from =>
                                from.DeliveryAddresses != null && from.DeliveryAddresses.Count > 0
                                    ? from.DeliveryAddresses[0]
                                    : null))
                .ForMember(to => to.PersonInformation,
                    opts => opts.MapFrom(from => Mapper.Map<Customer, TPersonInformationModel>(from)))
                .ForMember(to => to.SocialSecurityNumber, opts => opts.MapFrom(from => from.SSN));

            Mapper.CreateMap<Customer, TCheckoutCompanyShipToModel>()
                .ForMember(to => to.DeliveryAddress,
                    opts =>
                        opts.MapFrom(
                            from =>
                                from.Companies != null && from.Companies.Count > 0 &&
                                from.Companies[0].DeliveryAddresses != null &&
                                from.Companies[0].DeliveryAddresses.Count > 0
                                    ? from.Companies[0].DeliveryAddresses[0]
                                    : null))
                .ForMember(to => to.CompanyId,
                    opts =>
                        opts.MapFrom(
                            from => from.Companies != null && from.Companies.Count > 0
                                ? from.Companies[0].Id
                                : null))
                .ForMember(to => to.CompanyCode,
                    opts =>
                        opts.MapFrom(
                            from => from.Companies != null && from.Companies.Count > 0
                                ? from.Companies[0].Code
                                : null))
                .ForMember(to => to.CompanyInformation,
                    opts =>
                        opts.MapFrom(
                            from =>
                                from.Companies != null && from.Companies.Count > 0
                                    ? Mapper.Map<Company, TCompanyInformationModel>(from.Companies[0])
                                    : null))
                .ForMember(to => to.OrganisationNumber,
                    opts =>
                        opts.MapFrom(
                            from =>
                                from.Companies != null && from.Companies.Count > 0
                                    ? from.Companies[0].OrgNo
                                    : null));

            //CheckoutShipToModel -> Customer
            Mapper.CreateMap<CheckoutShipToBaseModel<TAddressModel>, Customer>()
                .ForMember(to => to.Id, opts => opts.MapFrom(from => from.CustomerId))
                .ForMember(to => to.Key, opts => opts.Ignore())
                .ForMember(to => to.Code, opts => opts.Ignore())
                .ForMember(to => to.SSN, opts => opts.Ignore())
                .ForMember(to => to.FirstName, opts => opts.Ignore())
                .ForMember(to => to.LastName, opts => opts.Ignore())
                .ForMember(to => to.Email, opts => opts.Ignore())
                .ForMember(to => to.Phone, opts => opts.Ignore())
                .ForMember(to => to.CellPhone, opts => opts.Ignore())
                .ForMember(to => to.ReferId, opts => opts.Ignore())
                .ForMember(to => to.ReferUrl, opts => opts.Ignore())
                .ForMember(to => to.Account, opts => opts.Ignore())
                .ForMember(to => to.Companies, opts => opts.Ignore())
                .ForMember(to => to.InvoiceAddress, opts => opts.Ignore())
                .ForMember(to => to.DeliveryAddresses, opts => opts.Ignore())
                .ForMember(to => to.Flags, opts => opts.Ignore())
                .ForMember(to => to.UseInvoiceAddressAsDeliveryAddress, opts => opts.Ignore())
                .ForMember(to => to.Info, opts => opts.Ignore())
                .ForMember(to => to.ExtensionData, opts => opts.Ignore())
                .Include<TCheckoutPrivateShipToModel, Customer>()
                .Include<TCheckoutCompanyShipToModel, Customer>();

            Mapper.CreateMap<TCheckoutPrivateShipToModel, Customer>()
                .ForMember(to => to.DeliveryAddresses, opts => opts.MapFrom(from => new AddressList {Mapper.Map<TAddressModel, Address>(from.DeliveryAddress)}))
                .ForMember(to => to.SSN, opts => opts.MapFrom(from => from.SocialSecurityNumber));

            Mapper.CreateMap<TCheckoutCompanyShipToModel, Customer>()
                .BeforeMap((from, to) =>
                {
                    var company = Mapper.Map<TCompanyInformationModel, Company>(from.CompanyInformation);
                    company.Id = from.CompanyId;
                    company.Code = from.CompanyCode;
                    company.OrgNo = from.OrganisationNumber;
                    company.DeliveryAddresses = new AddressList
                    {
                        Mapper.Map<TAddressModel, Address>(from.DeliveryAddress)
                    };
                    to.Companies = new CompanyList { company };
                });


            //Checkout -> PrivateCheckoutModel
            Mapper.CreateMap<Checkout, TPrivateCheckoutModel>()
                .ForMember(to => to.Buyer,
                    opts => opts.MapFrom(
                        from =>
                            Mapper.Map<Customer, TCheckoutBuyerModel>(from.Buyer)))
                .ForMember(to => to.Payer,
                    opts =>
                        opts.MapFrom(
                            from =>
                                Mapper.Map<Customer, TCheckoutPrivatePayerModel>(from.Payer)))
                .ForMember(to => to.ShipTo,
                    opts =>
                        opts.MapFrom(
                            from =>
                                Mapper.Map<Customer, TCheckoutPrivateShipToModel>(from.ShipTo)))
                .ForMember(to => to.OrderReference, opts => opts.MapFrom(from => from.Basket.OrderReference));


            //Checkout -> CompanyCheckoutModel
            Mapper.CreateMap<Checkout, TCompanyCheckoutModel>()
                .ForMember(to => to.Buyer,
                    opts => opts.MapFrom(
                        from =>
                            Mapper.Map<Customer, TCheckoutBuyerModel>(from.Buyer)))
                .ForMember(to => to.Payer,
                    opts =>
                        opts.MapFrom(
                            from =>
                                Mapper.Map<Customer, TCheckoutCompanyPayerModel>(from.Payer)))
                .ForMember(to => to.ShipTo,
                    opts =>
                        opts.MapFrom(
                            from =>
                                Mapper.Map<Customer, TCheckoutCompanyShipToModel>(from.ShipTo)))
                .ForMember(to => to.OrderReference, opts => opts.MapFrom(from => from.Basket.OrderReference));


        }

        public override string ProfileName
        {
            get { return GetType().Name; }
        }
    }
}
